<template>
  <div class="video-stream-container">
    <div class="stream-header">
      <h2>{{ title || '视频流检测' }}</h2>
      <div class="stream-controls">
        <el-button-group>
          <el-button type="primary" size="small" @click="startStream" :disabled="isStreaming">开始</el-button>
          <el-button type="danger" size="small" @click="stopStream" :disabled="!isStreaming">停止</el-button>
          <el-button type="info" size="small" @click="captureSnapshot" :disabled="!isStreaming">截图</el-button>
        </el-button-group>
        
        <el-dropdown @command="changeResolution">
          <el-button size="small">
            分辨率 <el-icon class="el-icon--right"><arrow-down /></el-icon>
          </el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item command="480p">480p</el-dropdown-item>
              <el-dropdown-item command="720p">720p</el-dropdown-item>
              <el-dropdown-item command="1080p">1080p</el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </div>
    
    <div class="stream-content">
      <!-- 视频预览区域 -->
      <div class="video-wrapper">
        <video 
          ref="videoRef"
          autoplay 
          muted 
          playsinline 
          class="video-element"
          :width="videoWidth" 
          :height="videoHeight"
        ></video>
        <canvas 
          ref="canvasRef"
          class="detection-canvas"
          :width="videoWidth" 
          :height="videoHeight"
        ></canvas>
        
        <!-- 加载提示 -->
        <div v-if="isLoading" class="loading-overlay">
          <el-icon size="48" color="#1890ff"><loading /></el-icon>
          <p>正在连接视频流...</p>
        </div>
        
        <!-- 错误提示 -->
        <div v-if="hasError" class="error-overlay">
          <el-icon size="48" color="#f56c6c"><warning /></el-icon>
          <p>{{ errorMessage }}</p>
          <el-button type="primary" size="small" @click="startStream">重试</el-button>
        </div>
      </div>
      
      <!-- 控制面板 -->
      <div class="control-panel">
        <h3>检测控制</h3>
        
        <el-form label-position="top">
          <el-form-item label="检测选项">
            <el-checkbox-group v-model="detectionOptions" @change="updateDetectionOptions">
              <el-checkbox label="person">行人</el-checkbox>
              <el-checkbox label="car">汽车</el-checkbox>
              <el-checkbox label="bicycle">自行车</el-checkbox>
              <el-checkbox label="motorcycle">摩托车</el-checkbox>
              <el-checkbox label="truck">货车</el-checkbox>
              <el-checkbox label="helmet">戴头盔</el-checkbox>
              <el-checkbox label="no_helmet">未戴头盔</el-checkbox>
            </el-checkbox-group>
          </el-form-item>
          
          <el-form-item label="置信度阈值" prop="confidenceThreshold">
            <el-slider 
              v-model="confidenceThreshold" 
              :min="0.1" 
              :max="1.0" 
              :step="0.05"
              :marks="{ 0.1: '0.1', 0.5: '0.5', 0.9: '0.9' }"
              @change="updateConfidenceThreshold"
            />
            <div class="threshold-value">当前值: {{ confidenceThreshold.toFixed(2) }}</div>
          </el-form-item>
          
          <el-form-item label="显示选项">
            <el-checkbox v-model="showLabels" @change="updateDisplayOptions">显示标签</el-checkbox>
            <el-checkbox v-model="showConfidence" @change="updateDisplayOptions">显示置信度</el-checkbox>
            <el-checkbox v-model="showTrackingId" @change="updateDisplayOptions">显示跟踪ID</el-checkbox>
          </el-form-item>
        </el-form>
        
        <!-- 实时统计 -->
        <div class="realtime-stats">
          <h3>实时统计</h3>
          <div class="stats-grid">
            <el-statistic 
              v-for="(count, class_name) in currentStats" 
              :key="class_name"
              class="stat-item"
              :title="getClassNameCN(class_name)"
              :value="count"
              :value-style="{ color: getClassColor(class_name) }"
            />
          </div>
          <div v-if="Object.keys(currentStats).length === 0" class="no-stats">
            暂无检测结果
          </div>
        </div>
      </div>
    </div>
    
    <!-- 最近检测历史 -->
    <div v-if="recentDetections.length > 0" class="detection-history">
      <h3>最近检测历史</h3>
      <el-scrollbar height="150px">
        <el-timeline>
          <el-timeline-item 
            v-for="(detection, index) in recentDetections.slice(0, 5)" 
            :key="index"
            :timestamp="formatTime(detection.timestamp)"
            :type="getAlertType(detection.class_name)"
          >
            <div class="detection-item">
              <span class="detection-class" :style="{ color: getClassColor(detection.class_name) }">
                {{ getClassNameCN(detection.class_name) }}
              </span>
              <span class="detection-confidence">({{ Math.round(detection.confidence * 100) }}%)</span>
              <span class="detection-position">位置: ({{ Math.round(detection.x) }}, {{ Math.round(detection.y) }})</span>
            </div>
          </el-timeline-item>
        </el-timeline>
      </el-scrollbar>
    </div>
    
    <!-- 截图预览对话框 -->
    <el-dialog v-model="showSnapshotDialog" title="截图预览" width="800px">
      <img :src="snapshotData" alt="Snapshot" class="snapshot-image" />
      <template #footer>
        <el-button @click="showSnapshotDialog = false">关闭</el-button>
        <el-button type="primary" @click="downloadSnapshot">下载</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { ElMessage } from 'element-plus'

export default {
  name: 'VideoStream',
  props: {
    title: {
      type: String,
      default: ''
    },
    source: {
      type: String,
      default: 'camera' // camera, video, rtsp
    },
    sourceUrl: {
      type: String,
      default: ''
    },
    cameraId: {
      type: Number,
      default: null
    }
  },
  setup(props) {
    // 引用
    const videoRef = ref(null)
    const canvasRef = ref(null)
    
    // 状态
    const isStreaming = ref(false)
    const isLoading = ref(false)
    const hasError = ref(false)
    const errorMessage = ref('')
    const showSnapshotDialog = ref(false)
    const snapshotData = ref('')
    
    // 配置
    const videoWidth = ref(640)
    const videoHeight = ref(360)
    const confidenceThreshold = ref(0.5)
    const showLabels = ref(true)
    const showConfidence = ref(true)
    const showTrackingId = ref(false)
    const detectionOptions = ref(['person', 'car', 'bicycle', 'motorcycle', 'helmet', 'no_helmet'])
    
    // 数据
    const currentDetections = ref([])
    const recentDetections = ref([])
    
    // 定时器和请求
    let detectionInterval = null
    let mediaStream = null
    
    // 计算属性 - 当前统计
    const currentStats = computed(() => {
      const stats = {}
      currentDetections.value.forEach(detection => {
        if (detectionOptions.value.includes(detection.class_name)) {
          stats[detection.class_name] = (stats[detection.class_name] || 0) + 1
        }
      })
      return stats
    })
    
    // 开始视频流
    const startStream = async () => {
      isLoading.value = true
      hasError.value = false
      
      try {
        if (props.source === 'camera') {
          await startCameraStream()
        } else if (props.source === 'rtsp' && props.sourceUrl) {
          await startRTSPStream()
        } else if (props.source === 'video' && props.sourceUrl) {
          await startVideoFileStream()
        } else if (props.cameraId) {
          await startServerStream()
        } else {
          throw new Error('未指定有效的视频源')
        }
        
        isStreaming.value = true
        startDetection()
        ElMessage.success('视频流启动成功')
      } catch (error) {
        console.error('启动视频流失败:', error)
        hasError.value = true
        errorMessage.value = error.message || '启动视频流失败'
        ElMessage.error('启动视频流失败: ' + error.message)
      } finally {
        isLoading.value = false
      }
    }
    
    // 启动摄像头流
    const startCameraStream = async () => {
      mediaStream = await navigator.mediaDevices.getUserMedia({
        video: {
          width: videoWidth.value,
          height: videoHeight.value
        }
      })
      videoRef.value.srcObject = mediaStream
    }
    
    // 启动RTSP流
    const startRTSPStream = async () => {
      // 实际项目中，这里应该通过WebSocket或后端代理获取RTSP流转码后的流
      // 这里使用模拟数据
      videoRef.value.src = '/api/rtsp-proxy?url=' + encodeURIComponent(props.sourceUrl)
    }
    
    // 启动视频文件流
    const startVideoFileStream = async () => {
      videoRef.value.src = props.sourceUrl
      videoRef.value.play()
    }
    
    // 启动服务器流
    const startServerStream = async () => {
      // 从后端API获取摄像头流
      videoRef.value.src = `/api/cameras/${props.cameraId}/stream?with_overlay=${showLabels.value}`
    }
    
    // 停止视频流
    const stopStream = () => {
      isStreaming.value = false
      
      // 停止检测
      if (detectionInterval) {
        clearInterval(detectionInterval)
        detectionInterval = null
      }
      
      // 释放媒体流
      if (mediaStream) {
        mediaStream.getTracks().forEach(track => track.stop())
        mediaStream = null
      }
      
      // 清空视频
      if (videoRef.value) {
        videoRef.value.srcObject = null
        videoRef.value.src = ''
      }
      
      // 清空画布
      if (canvasRef.value) {
        const ctx = canvasRef.value.getContext('2d')
        ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)
      }
      
      // 清空检测数据
      currentDetections.value = []
      
      ElMessage.success('视频流已停止')
    }
    
    // 开始检测
    const startDetection = () => {
      // 模拟检测，实际项目中应该调用后端API或使用WebAssembly版YOLO
      detectionInterval = setInterval(async () => {
        if (!isStreaming.value || !videoRef.value) return
        
        try {
          // 模拟检测结果
          const detections = await performMockDetection()
          currentDetections.value = detections
          
          // 记录最近检测
          detections.forEach(detection => {
            if (detection.confidence > confidenceThreshold.value && 
                detectionOptions.value.includes(detection.class_name)) {
              recentDetections.value.unshift({
                ...detection,
                timestamp: new Date()
              })
              // 保留最近20条记录
              if (recentDetections.value.length > 20) {
                recentDetections.value = recentDetections.value.slice(0, 20)
              }
            }
          })
          
          // 绘制检测结果
          drawDetections(detections)
        } catch (error) {
          console.error('执行检测失败:', error)
        }
      }, 1000) // 每秒检测一次
    }
    
    // 模拟检测
    const performMockDetection = async () => {
      // 生成随机检测结果
      const possibleClasses = detectionOptions.value
      const detections = []
      const detectionCount = Math.floor(Math.random() * 5) + 1 // 1-5个检测目标
      
      for (let i = 0; i < detectionCount; i++) {
        const classIndex = Math.floor(Math.random() * possibleClasses.length)
        const className = possibleClasses[classIndex]
        const confidence = Math.random() * 0.5 + 0.5 // 0.5-1.0的置信度
        
        if (confidence > confidenceThreshold.value) {
          detections.push({
            id: i,
            class_name: className,
            confidence: confidence,
            x: Math.floor(Math.random() * (videoWidth.value - 100)) + 50,
            y: Math.floor(Math.random() * (videoHeight.value - 100)) + 50,
            width: Math.floor(Math.random() * 80) + 40,
            height: Math.floor(Math.random() * 80) + 40
          })
        }
      }
      
      return detections
    }
    
    // 绘制检测结果
    const drawDetections = (detections) => {
      if (!canvasRef.value) return
      
      const ctx = canvasRef.value.getContext('2d')
      ctx.clearRect(0, 0, canvasRef.value.width, canvasRef.value.height)
      
      detections.forEach(detection => {
        if (detection.confidence > confidenceThreshold.value && 
            detectionOptions.value.includes(detection.class_name)) {
          // 绘制边界框
          ctx.strokeStyle = getClassColor(detection.class_name)
          ctx.lineWidth = 2
          ctx.strokeRect(detection.x, detection.y, detection.width, detection.height)
          
          // 绘制标签
          if (showLabels.value) {
            const label = showConfidence.value 
              ? `${getClassNameCN(detection.class_name)} (${Math.round(detection.confidence * 100)}%)`
              : getClassNameCN(detection.class_name)
              
            if (showTrackingId.value) {
              label += ` ID:${detection.id}`
            }
            
            ctx.fillStyle = getClassColor(detection.class_name)
            ctx.fillStyle = 'rgba(0, 0, 0, 0.7)'
            ctx.font = '12px Arial'
            const textWidth = ctx.measureText(label).width + 10
            const textHeight = 18
            
            // 标签背景
            ctx.fillRect(detection.x, detection.y - textHeight, textWidth, textHeight)
            
            // 标签文字
            ctx.fillStyle = 'white'
            ctx.fillText(label, detection.x + 5, detection.y - 5)
          }
        }
      })
    }
    
    // 截图
    const captureSnapshot = () => {
      if (!videoRef.value || !canvasRef.value) {
        ElMessage.warning('没有可截图的内容')
        return
      }
      
      const tempCanvas = document.createElement('canvas')
      tempCanvas.width = videoWidth.value
      tempCanvas.height = videoHeight.value
      const ctx = tempCanvas.getContext('2d')
      
      // 先绘制视频帧
      ctx.drawImage(videoRef.value, 0, 0, videoWidth.value, videoHeight.value)
      
      // 再绘制检测结果
      ctx.drawImage(canvasRef.value, 0, 0)
      
      // 转换为图片数据
      snapshotData.value = tempCanvas.toDataURL('image/png')
      showSnapshotDialog.value = true
      ElMessage.success('截图成功')
    }
    
    // 下载截图
    const downloadSnapshot = () => {
      const link = document.createElement('a')
      link.href = snapshotData.value
      link.download = `snapshot_${new Date().getTime()}.png`
      link.click()
      ElMessage.success('截图已下载')
    }
    
    // 更改分辨率
    const changeResolution = (resolution) => {
      switch (resolution) {
        case '480p':
          videoWidth.value = 854
          videoHeight.value = 480
          break
        case '720p':
          videoWidth.value = 1280
          videoHeight.value = 720
          break
        case '1080p':
          videoWidth.value = 1920
          videoHeight.value = 1080
          break
      }
      
      // 如果正在直播，重新启动
      if (isStreaming.value) {
        stopStream()
        nextTick(() => {
          startStream()
        })
      }
      
      ElMessage.success(`分辨率已切换为 ${resolution}`)
    }
    
    // 更新检测选项
    const updateDetectionOptions = () => {
      ElMessage.success('检测选项已更新')
    }
    
    // 更新置信度阈值
    const updateConfidenceThreshold = () => {
      ElMessage.success(`置信度阈值已设置为 ${confidenceThreshold.value.toFixed(2)}`)
    }
    
    // 更新显示选项
    const updateDisplayOptions = () => {
      ElMessage.success('显示选项已更新')
    }
    
    // 获取类别颜色
    const getClassColor = (className) => {
      const colorMap = {
        'person': '#ff4d4f',
        'car': '#1890ff',
        'bicycle': '#52c41a',
        'motorcycle': '#faad14',
        'truck': '#722ed1',
        'helmet': '#52c41a',
        'no_helmet': '#ff4d4f'
      }
      return colorMap[className] || '#d9d9d9'
    }
    
    // 获取中文类别名称
    const getClassNameCN = (className) => {
      const nameMap = {
        'person': '行人',
        'car': '汽车',
        'bicycle': '自行车',
        'motorcycle': '摩托车',
        'truck': '货车',
        'helmet': '戴头盔',
        'no_helmet': '未戴头盔'
      }
      return nameMap[className] || className
    }
    
    // 获取告警类型
    const getAlertType = (className) => {
      if (className === 'no_helmet') return 'danger'
      if (className === 'person' || className === 'car') return 'primary'
      return 'success'
    }
    
    // 格式化时间
    const formatTime = (date) => {
      const d = new Date(date)
      return `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}:${d.getSeconds().toString().padStart(2, '0')}`
    }
    
    // 组件卸载时清理资源
    onUnmounted(() => {
      stopStream()
    })
    
    return {
      videoRef,
      canvasRef,
      isStreaming,
      isLoading,
      hasError,
      errorMessage,
      showSnapshotDialog,
      snapshotData,
      videoWidth,
      videoHeight,
      confidenceThreshold,
      showLabels,
      showConfidence,
      showTrackingId,
      detectionOptions,
      currentDetections,
      recentDetections,
      currentStats,
      startStream,
      stopStream,
      captureSnapshot,
      downloadSnapshot,
      changeResolution,
      updateDetectionOptions,
      updateConfidenceThreshold,
      updateDisplayOptions,
      getClassColor,
      getClassNameCN,
      getAlertType,
      formatTime
    }
  }
}
</script>

<style scoped>
.video-stream-container {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.stream-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 15px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.stream-header h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
}

.stream-controls {
  display: flex;
  gap: 15px;
  align-items: center;
}

.stream-content {
  display: flex;
  gap: 20px;
  flex: 1;
  min-height: 0;
}

.video-wrapper {
  position: relative;
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000;
  border-radius: 4px;
  overflow: hidden;
}

.video-element {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.detection-canvas {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
}

.loading-overlay,
.error-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  gap: 15px;
}

.loading-overlay p,
.error-overlay p {
  margin: 0;
  font-size: 16px;
}

.control-panel {
  width: 350px;
  background-color: #f5f7fa;
  border-radius: 4px;
  padding: 20px;
  overflow-y: auto;
}

.control-panel h3 {
  margin-top: 0;
  margin-bottom: 15px;
  font-size: 16px;
  font-weight: 500;
}

.threshold-value {
  text-align: center;
  margin-top: 5px;
  font-size: 14px;
  color: #606266;
}

.realtime-stats {
  margin-top: 30px;
}

.stats-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.stat-item {
  background-color: white;
  padding: 10px;
  border-radius: 4px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.no-stats {
  text-align: center;
  padding: 20px;
  color: #8c8c8c;
  font-style: italic;
}

.detection-history {
  margin-top: 20px;
  padding: 20px;
  background-color: #f5f7fa;
  border-radius: 4px;
}

.detection-history h3 {
  margin-top: 0;
  margin-bottom: 15px;
  font-size: 16px;
  font-weight: 500;
}

.detection-item {
  display: flex;
  align-items: center;
  gap: 10px;
}

.detection-class {
  font-weight: 500;
}

.detection-confidence {
  color: #606266;
  font-size: 14px;
}

.detection-position {
  color: #909399;
  font-size: 12px;
}

.snapshot-image {
  max-width: 100%;
  max-height: 60vh;
  object-fit: contain;
  display: block;
  margin: 0 auto;
}

/* 响应式设计 */
@media (max-width: 1024px) {
  .stream-content {
    flex-direction: column;
  }
  
  .control-panel {
    width: 100%;
    max-height: 400px;
  }
}
</style>